package cn.iocoder.yudao.module.system.service.scoreassignment;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.scoreassignment.vo.*;
import cn.iocoder.yudao.module.system.convert.scoreassignment.ScoreAssignmentRuleConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.scoreassignment.ScoreAssignmentRuleDO;
import cn.iocoder.yudao.module.system.dal.mysql.scoreassignment.ScoreAssignmentRuleMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 赋分计算 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class ScoreAssignmentServiceImpl implements ScoreAssignmentService {

    @Resource
    private ScoreAssignmentRuleMapper scoreAssignmentRuleMapper;

    @Override
    public Long createScoreAssignmentRule(@Valid ScoreAssignmentRuleCreateReqVO createReqVO) {
        // 插入
        ScoreAssignmentRuleDO rule = ScoreAssignmentRuleConvert.INSTANCE.convert(createReqVO);
        scoreAssignmentRuleMapper.insert(rule);
        // 返回
        return rule.getId();
    }

    @Override
    public void updateScoreAssignmentRule(@Valid ScoreAssignmentRuleUpdateReqVO updateReqVO) {
        // 校验存在
        validateScoreAssignmentRuleExists(updateReqVO.getId());
        // 更新
        ScoreAssignmentRuleDO updateObj = ScoreAssignmentRuleConvert.INSTANCE.convert(updateReqVO);
        scoreAssignmentRuleMapper.updateById(updateObj);
    }

    @Override
    public void deleteScoreAssignmentRule(Long id) {
        // 校验存在
        validateScoreAssignmentRuleExists(id);
        // 删除
        scoreAssignmentRuleMapper.deleteById(id);
    }

    private void validateScoreAssignmentRuleExists(Long id) {
        if (scoreAssignmentRuleMapper.selectById(id) == null) {
            throw exception(SCORE_ASSIGNMENT_RULE_NOT_EXISTS);
        }
    }

    @Override
    public ScoreAssignmentRuleDO getScoreAssignmentRule(Long id) {
        return scoreAssignmentRuleMapper.selectById(id);
    }

    @Override
    public List<ScoreAssignmentRuleDO> getScoreAssignmentRuleList(Collection<Long> ids) {
        return scoreAssignmentRuleMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<ScoreAssignmentRuleDO> getScoreAssignmentRulePage(ScoreAssignmentRulePageReqVO pageReqVO) {
        return scoreAssignmentRuleMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ScoreAssignmentRuleDO> getScoreAssignmentRuleList(ScoreAssignmentRulePageReqVO exportReqVO) {
        return scoreAssignmentRuleMapper.selectList(exportReqVO);
    }

    @Override
    public ScoreAssignmentResult calculateAssignedScore(String subjectName, BigDecimal originalScore, List<BigDecimal> allScores) {
        try {
            // 验证输入参数
            if (subjectName == null || originalScore == null || allScores == null || allScores.isEmpty()) {
                return new ScoreAssignmentResult("输入参数不能为空");
            }

            // 获取该科目的赋分规则
            List<ScoreAssignmentRuleDO> rules = getSubjectAssignmentRules(subjectName);
            if (rules.isEmpty()) {
                return new ScoreAssignmentResult("未找到科目 " + subjectName + " 的赋分规则");
            }

            // 计算百分比排名
            Double percentage = calculatePercentage(originalScore, allScores);
            
            // 根据百分比查找对应的赋分规则
            ScoreAssignmentRuleDO matchedRule = findMatchingRule(rules, percentage);
            if (matchedRule == null) {
                return new ScoreAssignmentResult("未找到匹配的赋分规则，百分比：" + percentage);
            }

            // 计算赋分
            BigDecimal assignedScore = calculateAssignedScoreByRule(matchedRule, percentage);
            
            return new ScoreAssignmentResult(
                assignedScore,
                matchedRule.getGradeLevel(),
                percentage,
                matchedRule.getDescription()
            );
            
        } catch (Exception e) {
            return new ScoreAssignmentResult("赋分计算失败：" + e.getMessage());
        }
    }

    @Override
    public List<ScoreAssignmentResult> batchCalculateAssignedScore(String subjectName, List<BigDecimal> scoreList) {
        List<ScoreAssignmentResult> results = new ArrayList<>();
        
        for (BigDecimal score : scoreList) {
            ScoreAssignmentResult result = calculateAssignedScore(subjectName, score, scoreList);
            results.add(result);
        }
        
        return results;
    }

    @Override
    public ScoreAssignmentResult calculateAssignedScoreByPercentage(String subjectName, Double percentage) {
        try {
            // 获取该科目的赋分规则
            List<ScoreAssignmentRuleDO> rules = getSubjectAssignmentRules(subjectName);
            if (rules.isEmpty()) {
                return new ScoreAssignmentResult("未找到科目 " + subjectName + " 的赋分规则");
            }

            // 根据百分比查找对应的赋分规则
            ScoreAssignmentRuleDO matchedRule = findMatchingRule(rules, percentage);
            if (matchedRule == null) {
                return new ScoreAssignmentResult("未找到匹配的赋分规则，百分比：" + percentage);
            }

            // 计算赋分
            BigDecimal assignedScore = calculateAssignedScoreByRule(matchedRule, percentage);
            
            return new ScoreAssignmentResult(
                assignedScore,
                matchedRule.getGradeLevel(),
                percentage,
                matchedRule.getDescription()
            );
            
        } catch (Exception e) {
            return new ScoreAssignmentResult("赋分计算失败：" + e.getMessage());
        }
    }

    @Override
    public List<ScoreAssignmentRuleDO> getSubjectAssignmentRules(String subjectName) {
        return scoreAssignmentRuleMapper.selectEnabledBySubject(subjectName);
    }

    @Override
    public AssignmentRuleValidationResult validateAssignmentRules(String subjectName) {
        List<ScoreAssignmentRuleDO> rules = getSubjectAssignmentRules(subjectName);
        List<String> errorMessages = new ArrayList<>();
        List<String> warningMessages = new ArrayList<>();
        boolean hasGaps = false;
        boolean hasOverlaps = false;

        if (rules.isEmpty()) {
            errorMessages.add("科目 " + subjectName + " 没有配置赋分规则");
            return new AssignmentRuleValidationResult(false, errorMessages, warningMessages, false, false);
        }

        // 按百分比排序
        rules.sort(Comparator.comparing(ScoreAssignmentRuleDO::getMinPercentage));

        // 检查覆盖范围
        if (!rules.get(0).getMinPercentage().equals(BigDecimal.ZERO)) {
            errorMessages.add("赋分规则未覆盖0%的情况");
            hasGaps = true;
        }

        if (!rules.get(rules.size() - 1).getMaxPercentage().equals(new BigDecimal("100"))) {
            errorMessages.add("赋分规则未覆盖100%的情况");
            hasGaps = true;
        }

        // 检查连续性和重叠
        for (int i = 0; i < rules.size() - 1; i++) {
            ScoreAssignmentRuleDO current = rules.get(i);
            ScoreAssignmentRuleDO next = rules.get(i + 1);

            if (current.getMaxPercentage().compareTo(next.getMinPercentage()) < 0) {
                errorMessages.add(String.format("等级 %s 和 %s 之间存在空隙", 
                    current.getGradeLevel(), next.getGradeLevel()));
                hasGaps = true;
            } else if (current.getMaxPercentage().compareTo(next.getMinPercentage()) > 0) {
                errorMessages.add(String.format("等级 %s 和 %s 之间存在重叠", 
                    current.getGradeLevel(), next.getGradeLevel()));
                hasOverlaps = true;
            }
        }

        // 检查赋分范围
        for (ScoreAssignmentRuleDO rule : rules) {
            if (rule.getAssignedScoreMin().compareTo(rule.getAssignedScoreMax()) > 0) {
                errorMessages.add(String.format("等级 %s 的赋分范围无效：最小值大于最大值", 
                    rule.getGradeLevel()));
            }
        }

        boolean valid = errorMessages.isEmpty();
        return new AssignmentRuleValidationResult(valid, errorMessages, warningMessages, hasGaps, hasOverlaps);
    }

    @Override
    public void createDefaultAssignmentRules(String ruleName, List<String> subjectNames) {
        // 默认的等级配置（以浙江省为例）
        Object[][] defaultGrades = {
            {"A", 0.00, 15.00, 91.00, 100.00, "A等级：前15%"},
            {"B", 15.00, 50.00, 81.00, 90.00, "B等级：15%-50%"},
            {"C", 50.00, 85.00, 71.00, 80.00, "C等级：50%-85%"},
            {"D", 85.00, 97.00, 61.00, 70.00, "D等级：85%-97%"},
            {"E", 97.00, 100.00, 40.00, 60.00, "E等级：后3%"}
        };

        for (String subjectName : subjectNames) {
            // 检查是否已存在规则
            List<ScoreAssignmentRuleDO> existingRules = getSubjectAssignmentRules(subjectName);
            if (!existingRules.isEmpty()) {
                continue; // 跳过已存在规则的科目
            }

            // 为每个科目创建默认规则
            for (Object[] grade : defaultGrades) {
                ScoreAssignmentRuleDO rule = new ScoreAssignmentRuleDO();
                rule.setRuleName(ruleName);
                rule.setSubjectName(subjectName);
                rule.setGradeLevel((String) grade[0]);
                rule.setMinPercentage(new BigDecimal(grade[1].toString()));
                rule.setMaxPercentage(new BigDecimal(grade[2].toString()));
                rule.setAssignedScoreMin(new BigDecimal(grade[3].toString()));
                rule.setAssignedScoreMax(new BigDecimal(grade[4].toString()));
                rule.setDescription((String) grade[5]);
                rule.setStatus(1);
                
                scoreAssignmentRuleMapper.insert(rule);
            }
        }
    }

    @Override
    public void updateRuleStatus(Long id, Integer status) {
        // 校验存在
        validateScoreAssignmentRuleExists(id);
        
        // 更新状态
        ScoreAssignmentRuleDO updateObj = new ScoreAssignmentRuleDO();
        updateObj.setId(id);
        updateObj.setStatus(status);
        scoreAssignmentRuleMapper.updateById(updateObj);
    }

    /**
     * 计算百分比排名
     */
    private Double calculatePercentage(BigDecimal targetScore, List<BigDecimal> allScores) {
        // 过滤掉null值并排序
        List<BigDecimal> validScores = allScores.stream()
            .filter(Objects::nonNull)
            .sorted(Collections.reverseOrder()) // 降序排列
            .collect(Collectors.toList());

        if (validScores.isEmpty()) {
            return 0.0;
        }

        // 找到目标分数的排名
        int rank = 1;
        for (BigDecimal score : validScores) {
            if (targetScore.compareTo(score) >= 0) {
                break;
            }
            rank++;
        }

        // 计算百分比（排名越小，百分比越小）
        double percentage = ((double) (rank - 1) / validScores.size()) * 100;
        return Math.round(percentage * 100.0) / 100.0; // 保留两位小数
    }

    /**
     * 根据百分比查找匹配的赋分规则
     */
    private ScoreAssignmentRuleDO findMatchingRule(List<ScoreAssignmentRuleDO> rules, Double percentage) {
        for (ScoreAssignmentRuleDO rule : rules) {
            BigDecimal percentageBD = new BigDecimal(percentage.toString());
            if (percentageBD.compareTo(rule.getMinPercentage()) >= 0 && 
                percentageBD.compareTo(rule.getMaxPercentage()) <= 0) {
                return rule;
            }
        }
        return null;
    }

    /**
     * 根据规则和百分比计算赋分
     */
    private BigDecimal calculateAssignedScoreByRule(ScoreAssignmentRuleDO rule, Double percentage) {
        // 线性插值计算赋分
        BigDecimal percentageBD = new BigDecimal(percentage.toString());
        BigDecimal percentageRange = rule.getMaxPercentage().subtract(rule.getMinPercentage());
        BigDecimal scoreRange = rule.getAssignedScoreMax().subtract(rule.getAssignedScoreMin());
        
        if (percentageRange.compareTo(BigDecimal.ZERO) == 0) {
            // 如果百分比范围为0，返回最大赋分
            return rule.getAssignedScoreMax();
        }
        
        // 计算在该等级内的相对位置
        BigDecimal relativePosition = percentageBD.subtract(rule.getMinPercentage())
            .divide(percentageRange, 4, RoundingMode.HALF_UP);
        
        // 计算赋分（百分比越小，赋分越高）
        BigDecimal assignedScore = rule.getAssignedScoreMax()
            .subtract(scoreRange.multiply(relativePosition));
        
        // 保留一位小数
        return assignedScore.setScale(1, RoundingMode.HALF_UP);
    }

}